﻿using System;
using System.Diagnostics.Contracts;
using System.IO;
using System.Windows.Media;
using OpenLS.Drawing;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
    internal struct CFColor
    {
        private XColorType _xclrType;
        private uint _xclrValue;
        private double _numTint;

        public CFColor(SpreadsheetColor color)
        {
            if (color is ThemeColor)
            {
                _xclrType = XColorType.XCLRTHEMED;
                ThemeColor themeColor = (ThemeColor)color;
                this._xclrValue = (uint)themeColor.ColorIndex;
                this._numTint = themeColor.Tint.GetValueOrDefault(0) ;
            }
            else if (color is AutomaticColor)
            {
                _xclrType = XColorType.XCLRAUTO;
                throw new NotImplementedException();
            }
            else if (color is IndexedColor)
            {
                _xclrType = XColorType.XCLRINDEXED;
                IndexedColor indexedColor = (IndexedColor)color;
                this._xclrValue = (uint)indexedColor.Index;
                this._numTint = 0;
            }
            else if (color is RgbColor)
            {
                _xclrType = XColorType.XCLRRGB;

                RgbColor rgbColor = (RgbColor)color;
                var c = rgbColor.Color;
                this._xclrValue = (uint)(c.R | (c.G << 8) | (c.B << 16) | (c.A << 24));
                this._numTint = 0;
            }
            else
            {
                throw new NotSupportedException();
            }
            Contract.Assert(ToColor().Equals(color));
        }

        public CFColor(BinaryReader reader)
        {
            this._xclrValue = 0;
            this._numTint = 0;
            this._xclrType = 0;
            Read(reader);
        }

        public void Read(BinaryReader reader)
        {
            this._xclrType = (XColorType) reader.ReadInt32();
            this._xclrValue = reader.ReadUInt32();
            this._numTint = reader.ReadDouble();
        }

        public void Write(BinaryWriter writer)
        {
            writer.Write((int)_xclrType);
            writer.Write((int)_xclrValue);
            writer.Write(_numTint);
        }

        public SpreadsheetColor ToColor()
        {
            switch (_xclrType)
            {
                case XColorType.XCLRRGB:
                    var r = (byte)((_xclrValue >> 0) & 0xFF);
                    var g = (byte)((byte)(_xclrValue >> 8) & 0xFF);
                    var b = (byte)((byte)(_xclrValue >> 16) & 0xFF);
                    var a = (byte)((byte)(_xclrValue >> 24) & 0xFF);
                    return new RgbColor(Color.FromArgb(a, r, g, b));
                case XColorType.XCLRTHEMED:
                    var tint = Convert.ToDouble(this._numTint) ;
                    return new ThemeColor((ColorSchemeIndex)_xclrValue, false ? null : (double?)(tint == 0 ? (double?)null : tint));
                case XColorType.XCLRAUTO:
                    return new AutomaticColor(false); //\\
                case XColorType.XCLRINDEXED:
                case XColorType.XCLRNINCHED:
                    throw new NotImplementedException(_xclrType.ToString());
                default:
                    throw new NotSupportedException();
            }
        }
    }
}